//
//  StatzSource.m
//  Statz
//
//  Created by Dave MacLachlan on 07/07/23.
//
// Copyright 2007 Google Inc.
// 
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License.  You may obtain a copy
// of the License at
// 
// http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
// License for the specific language governing permissions and limitations under
// the License.
//

#import "StatzSource.h"
#import "StatzTextAttachment.h"
#import "StatzSourceTokenCell.h"
#import "Status.h"

const int kStatzStatusSourceCoderVersion = 1;
NSString *const kStatzStatusSourceCoderVersionKey = @"kStatzStatusSourceCoderVersionKey";
NSString *const kStatzStatusSourceStatusesKey = @"kStatzStatusSourceStatusesKey";
NSString *const kStatzStatusSourceCurrentKey = @"kStatzStatusSourceCurrentKey";
NSString *const kStatzStatusSourceDisplayInMenuKey = @"kStatzStatusSourceDisplayInMenuKey";
NSString *const kStatzStatusSourceAttachmentKey = @"kStatzStatusSourceAttachmentKey";

@implementation StatzSource
- (id)init {
  self = [super init];
  if (self != nil) {
    statuses_ = [[NSMutableArray array] retain];
    currentStatus_ = 0;
  }
  return self;
}

- (id)initWithName:(NSString*)name {
  if ((self = [super init])) {
    [self setName:name];
  }
  return self;
}

- (id)initWithCoder:(NSCoder *)aDecoder {
  if ((self = [super init])) {
    int version = [aDecoder decodeInt32ForKey:kStatzStatusSourceCoderVersionKey];
    if (version != kStatzStatusSourceCoderVersion) {
      [self release];
      return nil;
    }
    attachment_ = [[aDecoder decodeObjectForKey:kStatzStatusSourceAttachmentKey] retain];
    statuses_ = [[aDecoder decodeObjectForKey:kStatzStatusSourceStatusesKey] retain];
    currentStatus_ = [aDecoder decodeInt32ForKey:kStatzStatusSourceCurrentKey];
  }
  return self;
}

- (void)encodeWithCoder:(NSCoder *)aCoder {
  [aCoder encodeInt32:kStatzStatusSourceCoderVersion forKey:kStatzStatusSourceCoderVersionKey];
  [aCoder encodeObject:attachment_ forKey:kStatzStatusSourceAttachmentKey];
  [aCoder encodeObject:statuses_ forKey:kStatzStatusSourceStatusesKey];
  [aCoder encodeInt32:currentStatus_ forKey:kStatzStatusSourceCurrentKey];
}

- (void)dealloc {
  [statuses_ release];
  [attachment_ release];
  [super dealloc];
}

- (Status*)currentStatus {
  Status *currentStatus = nil;
  NSArray *statuses = [self statuses];
  if ([statuses count] > currentStatus_) {
    currentStatus = [statuses objectAtIndex:currentStatus_];
  }
  return [[currentStatus retain] autorelease];
}

- (void)setCurrentStatus:(Status*)status {  
  NSArray *statuses = [self statuses];
  unsigned int objectIndex = [statuses indexOfObject:status];
  if (objectIndex != NSNotFound) {
    currentStatus_ = objectIndex;
  }
}

- (unsigned int)currentStatusIndex {
  return currentStatus_;
}

- (void)setCurrentStatusIndex:(unsigned int)value {
  currentStatus_ = value;
}

- (NSImage *)image {
  return [NSImage imageNamed:@"NSApplicationIcon"]; 
}


- (NSString*)description {
  return [NSString stringWithFormat:@"StatzSource name: %@\nstatuses: %@", [self name], [self statuses]];
}

- (NSString*)name {
  return @"Hi!";
}

- (NSAttributedString *)displayNameAndStatus {
  NSMutableAttributedString *attributedStatus = [[[[self currentStatus] attributedStatus] mutableCopy] autorelease];
  NSString *string = [self name];

  NSDictionary *attrs = [NSDictionary dictionaryWithObjectsAndKeys:
                         [NSFont boldSystemFontOfSize:[NSFont smallSystemFontSize]], NSFontAttributeName,
                         [NSNumber numberWithFloat:4], NSBaselineOffsetAttributeName,
                                               nil];
  
  if (attributedStatus) string = [string stringByAppendingString:@"\r"];

  NSMutableAttributedString *aString = [[[NSMutableAttributedString alloc] initWithString:string attributes:attrs] autorelease];  
  
  if (attributedStatus) {
   [attributedStatus addAttribute:NSFontAttributeName 
                            value:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]
                            range:NSMakeRange(0, [attributedStatus length])];
    [aString appendAttributedString:attributedStatus];
  }
  return aString;
}

- (void)setName:(NSString*)name {
  NSAssert(NO, @"setName not implemented");
}

- (BOOL)isNameEditable {
  return YES;
}

- (NSAttributedString*)nameToken {
  if (!attachment_) {
    StatzSourceTokenCell *token = [[[StatzSourceTokenCell alloc] initTextCell:[self name]] autorelease];
    attachment_ = [[StatzTextAttachment alloc] initWithFileWrapper:nil];
    [attachment_ setAttachmentCell:token];
    [attachment_ setStatusSource:self];
  }
  return [NSAttributedString attributedStringWithAttachment:attachment_];
}

- (NSArray*)statuses {
  return [[statuses_ retain] autorelease];
}

- (void)addStatus:(Status*)status {
  if (![statuses_ containsObject:status]) {
    [statuses_ addObject:status];
  }
}  

- (void)removeStatus:(Status*)status {
    [statuses_ removeObject:status];
}  

- (BOOL)isValid {
  return YES;
}

- (BOOL)isEnabled {
  return YES;
}

- (void)addSourceDependenciesTo:(NSMutableArray*)array {
  NSEnumerator *statusEnum = [[self statuses] objectEnumerator];
  Status *status;
  while ((status = [statusEnum nextObject])) {
    [status addSourceDependenciesTo:array];
  }
}

- (id)plugin {
  return nil;
}
  
- (NSScriptObjectSpecifier *)objectSpecifier {
  NSScriptClassDescription *containerClassDesc = (NSScriptClassDescription *)
  [NSScriptClassDescription classDescriptionForClass:[NSApp class]];
    return [[[NSNameSpecifier alloc] initWithContainerClassDescription:containerClassDesc
             containerSpecifier:nil key:@"statusSources" name:[self name]] autorelease];
}

-(void)insertObject:(id)anObject inStatusesAtIndex:(unsigned)objectIndex {
  [statuses_ insertObject:anObject atIndex:objectIndex];
}

-(void)removeObjectFromStatusesAtIndex:(unsigned)objectIndex {
  [statuses_ removeObjectAtIndex:objectIndex];
}

-(void)replaceObjectInStatusesAtIndex:(unsigned)objectIndex withObject:(id)anObject {
  [statuses_ replaceObjectAtIndex:objectIndex withObject:anObject];
}

// Don't cause errors for undefined key value accesses
- (id)valueForUndefinedKey:(NSString *)key {
  return nil; 
}

- (NSMenu*)stateMenu { 
  return nil;
}

- (StatzState)state {
  return kStatzStateNone;
}

- (OSType)stateForScripting {
  return [[self class] scriptStateFromState:[self state]];
}

- (void)setStateForScripting:(OSType)newState {
  [self setState:[[self class] stateFromScriptState:newState]];
}

- (void)setState:(StatzState)state {
  NSLog(@"Tried to set state on a source");
}

+ (StatzState)stateFromScriptState:(OSType)scriptState  {
  int state = 0;
  switch(scriptState) {
    case 'aval':
      state = kStatzStateAvailable;
      break;
      
    case 'away':
      state = kStatzStateAway;
      break;
      
    case 'dnod':
      state = kStatzStateDoNotDisturb;
      break;
      
    case 'come':
      state = kStatzStateContactMe;
      break;      
      
    case 'invi':
      state = kStatzStateInvisible;
      break;
      
    case 'offl':
      state = kStatzStateOffline;
      break;      
      
    case 'none':
      state = kStatzStateNone;
      break;
      
    default:
      NSLog(@"Unexpected state");
      state = kStatzStateAway;
  }
  return state;
}

+ (OSType)scriptStateFromState:(StatzState)state {
  OSType scriptState = 0;
  switch(state) {
    case kStatzStateAvailable:
      state = 'aval';
      break;
      
    case kStatzStateAway:
      state = 'away';
      break;
      
    case kStatzStateDoNotDisturb:
      state = 'dnod';
      break;
      
    case kStatzStateContactMe:
      state = 'come';
      break;      
      
    case kStatzStateInvisible:
      state = 'invi';
      break;
      
    case kStatzStateOffline:
      state = 'offl';
      break;      
      
    case kStatzStateNone:
      state = 'none';
      break;
      
    default:
      NSLog(@"Unexpected state");
      scriptState = kStatzStateNone;
      break;
  }
  return scriptState;
}

- (BOOL)editableStatuses {
  return YES;
}
@end
